package org.activequant.data.retrieval.mock;

import org.activequant.core.domainmodel.InstrumentSpecification;
import org.activequant.core.domainmodel.data.MarketDataEntity;
import org.activequant.core.types.TimeFrame;
import org.activequant.data.annotations.Vendor;
import org.activequant.data.retrieval.SubscriptionSourceBase;

/**
 * Abstract mock source of subscriptions driven by a separate thread.
 * Use the concrete sub-classes for unit testing services that depend 
 * on subscription service. Supports only one outstanding subscription.
 * <br>
 * <b>History:</b><br>
 *  - [16.01.2008] Created (Erik Nijkamp)<br>
 *
 *  @author Erik Nijkamp
 */
@Vendor("Mock")
public abstract class MockThreadSubscriptionSourceBase<T extends MarketDataEntity<T>> extends SubscriptionSourceBase<T> {
	
	private static final int WAIT_MS = 2000;
	
	public MockThreadSubscriptionSourceBase() {
		super();
	}

	protected abstract T newElement(InstrumentSpecification spec, TimeFrame timeFrame);
	
	private class MockSubscription extends Subscription {
		private final InstrumentSpecification spec;
		private final TimeFrame timeFrame;
		private final Thread thread = new Thread() {
			public void run() {
				try {
					while(!isInterrupted()) {
						fire(newElement(spec, timeFrame));
						sleep(WAIT_MS);
					}
				} catch(InterruptedException ex) {
					/* ignored */
				} catch(Exception ex) {
					ex.printStackTrace();
				}
			}
		};
		
		public MockSubscription(InstrumentSpecification s, TimeFrame t) {
			spec = s;
			timeFrame = t;
		}

		@Override
		protected void handleActivate() {
			thread.start();
		}
		
		@Override
		protected void handleCancel() {
			thread.interrupt();
		}
		
		public void fire(T data) {
			super.fireEvent(data);
		}
	}
	

	@Override
	protected MockSubscription createSubscription(
			InstrumentSpecification spec, TimeFrame timeFrame) {
		return new MockSubscription(spec, timeFrame);
	}
	
}
